import axios from "axios"
import utils from "./utils.js"

const API_PER_PAGE = 100  // GitCode API max items per request

namespace api {
    export async function getRepoStargazers(repo: string, token?: string, page?: number) {
        let url = `https://api.gitcode.com/api/v5/repos/${repo}/stargazers?per_page=${API_PER_PAGE}`

        if (page !== undefined) {
            url = `${url}&page=${page}`
        }
        return axios.get(url, {
            headers: {
                Accept: "application/vnd.github.v3.star+json",
                Authorization: token ? `Bearer ${token}` : ""
            }
        })
    }

    export async function getRepoStargazersCount(repo: string, token?: string) {
        const { data } = await axios.get(`https://api.gitcode.com/api/v5/repos/${repo}`, {
            headers: {
                Accept: "application/vnd.github.v3.star+json",
                Authorization: token ? `Bearer ${token}` : ""
            }
        })

        return data.stargazers_count
    }

    export async function getRepoStarRecords(repo: string, token: string, maxRequestAmount: number) {
        const patchRes = await getRepoStargazers(repo, token)

        const headerLink = patchRes.headers["link"] || ""

        let pageCount = 1
        const regResult = /next.*&page=(\d*).*last/.exec(headerLink)

        if (regResult) {
            if (regResult[1] && Number.isInteger(Number(regResult[1]))) {
                pageCount = Number(regResult[1])
            }
        }

        if (pageCount === 1 && patchRes?.data?.length === 0) {
            throw {
                status: patchRes.status,
                data: []
            }
        }

        const requestPages: number[] = []
        if (pageCount < maxRequestAmount) {
            requestPages.push(...utils.range(1, pageCount))
        } else {
            utils.range(1, maxRequestAmount).map((i) => {
                requestPages.push(Math.round((i * pageCount) / maxRequestAmount) - 1)
            })
            if (!requestPages.includes(1)) {
                requestPages[0] = 1;
            }
        }

        const resArray = await Promise.all(
            requestPages.map((page) => {
                return getRepoStargazers(repo, token, page)
            })
        )

        const starRecordsMap: Map<string, number> = new Map()

        if (requestPages.length < maxRequestAmount) {
            const starRecordsData: {
                starred_at: string
            }[] = []
            resArray.map((res) => {
                const { data } = res
                starRecordsData.push(...data)
            })
            // Sort by starred_at ascending
            starRecordsData.sort((a, b) => new Date(a.starred_at).getTime() - new Date(b.starred_at).getTime())
            for (let i = 0; i < starRecordsData.length; ) {
                starRecordsMap.set(utils.getDateString(starRecordsData[i].starred_at), i + 1)
                i += Math.floor(starRecordsData.length / maxRequestAmount) || 1
            }
        } else {
            resArray.map(({ data }, index) => {
                if (data.length > 0) {
                    // Ensure per-page data is sorted ascending by starred_at
                    const sortedData = [...data].sort(
                        (a, b) => new Date(a.starred_at).getTime() - new Date(b.starred_at).getTime()
                    )
                    const starRecord = sortedData[0]
                    // Calculate actual star position based on API page size and position in page
                    const pageStartPosition = API_PER_PAGE * (requestPages[index] - 1)
                    starRecordsMap.set(utils.getDateString(starRecord.starred_at), pageStartPosition)
                }
            })
        }

        const starAmount = await getRepoStargazersCount(repo, token)
        starRecordsMap.set(utils.getDateString(Date.now()), starAmount)

        const starRecords: {
            date: string
            count: number
        }[] = []

        starRecordsMap.forEach((v, k) => {
            starRecords.push({
                date: k,
                count: v
            })
        })

        return starRecords
    }

    export async function getRepoLogoUrl(repo: string, token?: string): Promise<string> {
        const owner = repo.split("/")[0]
        try {
            const { data } = await axios.get(`https://api.gitcode.com/api/v5/users/${owner}`, {
            headers: {
                Accept: "application/vnd.github.v3.star+json",
                Authorization: token ? `Bearer ${token}` : ""
            }
        })

        return data.avatar_url
        } catch (error) {
            const { data } = await axios.get(`https://api.gitcode.com/api/v5/orgs/${owner}`, {
            headers: {
                Accept: "application/vnd.github.v3.star+json",
                Authorization: token ? `Bearer ${token}` : ""
            }
        })
        return data.avatar_url
        }
    }
}

export default api
